﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System.Net;
using System.Xml.Linq;
using System.Text.RegularExpressions;
using tiDE.Runtime;

namespace tiDE
{
    public partial class StartPage : DockContent
    {
        public event EventHandler NewProject, OpenProject;
        public event EventHandler<OpenProjectArgs> RecentProjectSelected;
        object lockObject = new object();
        List<FeedItem> Feed;
        bool CemetechDone = false, OmnimagaDone = false;
        bool CemetechFail = false, OmnimagaFail = false;

        public StartPage()
        {
            InitializeComponent();

            // Feed
            HttpWebRequest cemetechRequest = (HttpWebRequest)WebRequest.Create("http://cemetech.net/forum/rss.php");
            if (tiDEWindow.GlobalSettings.DisplayCemetechFeed)
                cemetechRequest.BeginGetResponse(CemetechFeedCallback, cemetechRequest);
            HttpWebRequest omnimagaRequest = (HttpWebRequest)WebRequest.Create("http://www.omnimaga.org/index.php?action=.xml;sa=recent;limit=10");
            if (tiDEWindow.GlobalSettings.DisplayOmnimagaFeed)
                omnimagaRequest.BeginGetResponse(OmnimagaFeedCallback, omnimagaRequest);
            if (!tiDEWindow.GlobalSettings.DisplayCemetechFeed && !tiDEWindow.GlobalSettings.DisplayOmnimagaFeed)
                label1.Text = "You haven't enabled any news feeds.  You can change this in Tools→Options→General→Start Page";

            // Recent Solutions
            if (tiDEWindow.GlobalSettings.RecentSolutions.Count == 0)
                return;
            flowLayoutPanel1.Controls.Clear();
            BinaryFormatter format = new BinaryFormatter();
            for (int i = tiDEWindow.GlobalSettings.RecentSolutions.Count - 1;
                i >= (tiDEWindow.GlobalSettings.RecentSolutions.Count - 10 < 0 ? 0 :
                tiDEWindow.GlobalSettings.RecentSolutions.Count - 10); i--)
            {
                string Solution = tiDEWindow.GlobalSettings.RecentSolutions[i];
                LinkLabel linkLabel = new LinkLabel();
                linkLabel.Tag = Solution;
                try
                {
                    Stream stream = File.Open(Solution, FileMode.Open);
                    linkLabel.Text = ((tiDE.API.Solution)format.Deserialize(stream)).Name;
                    linkLabel.Click += new EventHandler(linkLabel_Click);
                    stream.Close();
                    flowLayoutPanel1.Controls.Add(linkLabel);
                }
                catch { }
            }
        }

        void CemetechFeedCallback(IAsyncResult result)
        {
            try
            {
                HttpWebRequest request = (result.AsyncState as HttpWebRequest);
                HttpWebResponse resp = (HttpWebResponse)request.EndGetResponse(result);
                StreamReader stream = new StreamReader(resp.GetResponseStream());
                string rss = stream.ReadToEnd();
                stream.Close();
                rss = rss.Replace("xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:annotate=\"http://purl.org/rss/1.0/modules/annotate/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" version=\"2.0\"", "xml");
                rss = rss.Replace("dc:", "").Replace("annotate:", "").Replace("rdf:", "");
                XDocument document = XDocument.Parse(rss);
                lock (lockObject)
                {
                    if (Feed == null)
                        Feed = new List<FeedItem>();
                    foreach (XElement element in document.Root.Element("channel").Elements("item"))
                    {
                        FeedItem item = new FeedItem();
                        item.Title = element.Element("title").Value;
                        item.Link = element.Element("link").Value;
                        item.Date = DateTime.Parse(element.Element("pubDate").Value);
                        item.Date = item.Date.AddHours(2);
                        HtmlAgilityPack.HtmlDocument hDoc = new HtmlAgilityPack.HtmlDocument();
                        hDoc.LoadHtml(element.Element("description").Value);
                        item.Content = hDoc.DocumentNode.Element("span").InnerText;
                        Feed.Add(item);
                    }
                }
                CemetechDone = true;
                if (CemetechDone && OmnimagaDone)
                {
                    // Sort
                    Feed.Sort();
                    UpdateFeed();
                }
            }
            catch 
            {
                CemetechFail = true;
                if (CemetechFail && OmnimagaFail)
                {
                    ReportError();
                }
            }
        }

        void OmnimagaFeedCallback(IAsyncResult result)
        {
            try
            {
                HttpWebRequest request = (result.AsyncState as HttpWebRequest);
                HttpWebResponse resp = (HttpWebResponse)request.EndGetResponse(result);
                StreamReader stream = new StreamReader(resp.GetResponseStream());
                string rss = stream.ReadToEnd();
                stream.Close();
                rss = rss.Replace("xmlns:smf=\"http://www.simplemachines.org/\" xmlns=\"http://www.simplemachines.org/xml/recent\"", "").Replace("smf:", "");
                XDocument document = XDocument.Parse(rss);
                OmnimagaDone = true;
                lock (lockObject)
                {
                    if (Feed == null)
                        Feed = new List<FeedItem>();
                    foreach (XElement element in document.Root.Elements("recent-post"))
                    {
                        FeedItem item = new FeedItem();
                        item.Title = element.Element("subject").Value;
                        item.Date = DateTime.Parse(element.Element("time").Value.Replace("Today at", DateTime.Now.ToShortDateString()));
                        item.Content = element.Element("body").Value;
                        item.Link = element.Element("topic").Element("link").Value;
                        Feed.Add(item);
                    }
                }
                if (CemetechDone && OmnimagaDone)
                {
                    // Sort
                    Feed.Sort();
                    UpdateFeed();
                }
            }
            catch
            {
                OmnimagaFail = true;
                if (CemetechFail && OmnimagaFail)
                {
                    ReportError();
                }
            }
        }

        delegate void ReportErrorDelegate();
        void ReportError()
        {
            if (this.InvokeRequired)
                this.Invoke(new ReportErrorDelegate(ReportError));
            else
            {
                flowLayoutPanel2.Controls.Clear();
                Label errorLabel = new Label();
                errorLabel.Text = "Error retrieving news";
                errorLabel.AutoSize = true;
                flowLayoutPanel2.Controls.Add(errorLabel);
            }
        }

        delegate void UpdateFeedDelegate();
        void UpdateFeed()
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new UpdateFeedDelegate(UpdateFeed));
            }
            else
            {
                flowLayoutPanel2.Controls.Clear();
                foreach (FeedItem item in Feed)
                {
                    ForumPost post = new ForumPost();
                    if (item.Link.Contains("omnimaga"))
                    {
                        post.pictureBox1.Image = Image.FromFile(RuntimeData.tiDEDirectory + "omnimaga.ico");
                    }
                    else if (item.Link.Contains("cemetech"))
                    {
                        post.pictureBox1.Image = Image.FromFile(RuntimeData.tiDEDirectory + "cemetech.ico");
                    }
                    post.label1.Text = item.Title;
                    post.label2.Text = HtmlRemoval.StripTagsRegexCompiled(item.Content);
                    post.linkLabel1.Text = item.Link;
                    flowLayoutPanel2.Controls.Add(post);
                }
            }
        }

        void linkLabel_Click(object sender, EventArgs e)
        {
            if (RecentProjectSelected != null)
                RecentProjectSelected(this, new OpenProjectArgs() { ProjectFile = (sender as LinkLabel).Tag as string });
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (NewProject != null)
                NewProject(this, new EventArgs());
        }

        private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (OpenProject != null)
                OpenProject(this, new EventArgs());
        }
    }

    public class OpenProjectArgs : EventArgs
    {
        public string ProjectFile { get; set; }
    }

    class FeedItem : IComparable
    {
        public string Title { get; set; }
        public DateTime Date { get; set; }
        public string Link { get; set; }
        public string Content { get; set; }

        public int CompareTo(object obj)
        {
            return Date.CompareTo((obj as FeedItem).Date);
        }
    }

    /// <summary>
    /// Methods to remove HTML from strings.
    /// </summary>
    public static class HtmlRemoval
    {
        /// <summary>
        /// Remove HTML from string with Regex.
        /// </summary>
        public static string StripTagsRegex(string source)
        {
            return Regex.Replace(source, "<.*?>", string.Empty);
        }

        /// <summary>
        /// Compiled regular expression for performance.
        /// </summary>
        static Regex _htmlRegex = new Regex("<.*?>", RegexOptions.Compiled);

        /// <summary>
        /// Remove HTML from string with compiled Regex.
        /// </summary>
        public static string StripTagsRegexCompiled(string source)
        {
            return _htmlRegex.Replace(source, string.Empty);
        }

        /// <summary>
        /// Remove HTML tags from string using char array.
        /// </summary>
        public static string StripTagsCharArray(string source)
        {
            char[] array = new char[source.Length];
            int arrayIndex = 0;
            bool inside = false;

            for (int i = 0; i < source.Length; i++)
            {
                char let = source[i];
                if (let == '<')
                {
                    inside = true;
                    continue;
                }
                if (let == '>')
                {
                    inside = false;
                    continue;
                }
                if (!inside)
                {
                    array[arrayIndex] = let;
                    arrayIndex++;
                }
            }
            return new string(array, 0, arrayIndex);
        }
    }
}
